
/* p3_2.c: Initialize and display "Hello" on the LCD sing 4-bit data mode. All interface uses Port B */

/* This program strictly follows HD44780 datasheet for timing. You may want to adjust the amount of delay for your LCD controller. */

#include "TM4C123GH6PM.h"

#define LCD_PORT GPIOB 
#define RS 1    /* BIT0 mask */ 
#define RW 2    /* BIT1 mask */ 
#define EN 4    /* BIT2 mask */

void delayMs(int n);
void delayUs(int n);
void LCD_nibble_write(unsigned char data, unsigned char control);
void LCD_command(unsigned char command);
void LCD_data(unsigned char data);
void LCD_init(void);

int main(void)
{
    LCD_init();
    for(;;)
    {
        LCD_command(1);       /* clear display */
        LCD_command(0x80);    /* LCD cursor location */

        delayMs(500);
        LCD_data('H');
        LCD_data('e');
        LCD_data('l');
        LCD_data('l');
        LCD_data('o');
        delayMs(500);
    }
}

void LCD_init(void)
{
    SYSCTL->RCGCGPIO |= 0x02;   /* enable clock to GPIOB */ 
    LCD_PORT->DIR = 0xFF;       /* set all PORTB pins as output */
    LCD_PORT->DEN = 0xFF;       /* set all PORTB pins as digital pins */

    delayMs(20);                /* initialization sequence */
    LCD_nibble_write(0x30, 0);
    delayMs(5);
    LCD_nibble_write(0x30, 0);
    delayUs(100);
    LCD_nibble_write(0x30, 0);
    delayUs(40);

    LCD_nibble_write(0x20, 0);  /* use 4-bit data mode */
    delayUs(40);
    LCD_command(0x28);          /* set 4-bit data, 2-line, 5x7 font */
    LCD_command(0x06);          /* move cursor right */
    LCD_command(0x01);          /* clear screen, move cursor to home */
    LCD_command(0x0F);          /* turn on display, cursor blinking */
}

void LCD_nibble_write(unsigned char data, unsigned char control)
{
    data &= 0xF0;       /* clear lower nibble for control */
    control &= 0x0F;    /* clear upper nibble for data */
    LCD_PORT->DATA = data | control;       /* RS = 0, R/W = 0 */
    LCD_PORT->DATA = data | control | EN;  /* pulse E */
    delayUs(0);
    LCD_PORT->DATA = data;
    LCD_PORT->DATA = 0;
}

void LCD_command(unsigned char command)
{
    LCD_nibble_write(command & 0xF0, 0);   /* upper nibble first */
    LCD_nibble_write(command << 4, 0);     /* then lower nibble */
    
    if (command < 4)
        delayMs(2);         /* commands 1 and 2 need up to 1.64ms */
    else
        delayUs(40);        /* all others 40 us */
}

void LCD_data(unsigned char data)
{
    LCD_nibble_write(data & 0xF0, RS);    /* upper nibble first */
    LCD_nibble_write(data << 4, RS);      /* then lower nibble  */
    
    delayUs(40);
}


/* delay n milliseconds (16 MHz CPU clock) */
void delayMs(int n)
{
    int i, j;
    for(i = 0 ; i < n; i++)
        for(j = 0; j < 3180; j++)
            {}  /* do nothing for 1 ms */
}

/* delay n microseconds (16 MHz CPU clock) */
void delayUs(int n)
{
    int i, j;
    for(i = 0 ; i < n; i++)
        for(j = 0; j < 3; j++)
            {}  /* do nothing for 1 us */
}

/* This function is called by the startup assembly code to perform system specific initialization tasks. */
void SystemInit(void)
{
    /* Grant coprocessor access */
    /* This is required since TM4C123G has a floating point coprocessor */
    SCB->CPACR |= 0x00f00000;
}